scheduler_init();
idle_vcpu[0] = (struct vcpu*) ia64_r13;
- idle_domain = domain_create(IDLE_DOMAIN_ID, 0);
- BUG_ON(idle_domain == NULL);
+ idle_domain = domain_create(IDLE_DOMAIN_ID);
+ if ( (idle_domain == NULL) || (alloc_vcpu(idle_domain, 0, 0) == NULL) )
+ BUG();
late_setup_arch(&cmdline);
alloc_dom_xen_and_dom_io();
}
/* Create initial domain 0. */
- dom0 = domain_create(0, 0);
-
- if ( dom0 == NULL )
+ dom0 = domain_create(0);
+ if ( (dom0 == NULL) || (alloc_vcpu(dom0, 0, 0) == NULL) )
panic("Error creating domain 0\n");
set_bit(_DOMF_privileged, &dom0->domain_flags);
}
}
- if ( hvm_guest(d->vcpu[0]) )
+ if ( d->vcpu[0] && hvm_guest(d->vcpu[0]) )
hvm_relinquish_guest_resources(d);
shadow_mode_disable(d);
scheduler_init();
- idle_domain = domain_create(IDLE_DOMAIN_ID, 0);
- BUG_ON(idle_domain == NULL);
+ idle_domain = domain_create(IDLE_DOMAIN_ID);
+ if ( (idle_domain == NULL) || (alloc_vcpu(idle_domain, 0, 0) == NULL) )
+ BUG();
set_current(idle_domain->vcpu[0]);
this_cpu(curr_vcpu) = idle_domain->vcpu[0];
acm_init(&initrdidx, mbi, initial_images_start);
/* Create initial domain 0. */
- dom0 = domain_create(0, 0);
- if ( dom0 == NULL )
+ dom0 = domain_create(0);
+ if ( (dom0 == NULL) || (alloc_vcpu(dom0, 0, 0) == NULL) )
panic("Error creating domain 0\n");
set_bit(_DOMF_privileged, &dom0->domain_flags);
static void nmi_dom0_report(unsigned int reason_idx)
{
struct domain *d;
+ struct vcpu *v;
- if ( (d = dom0) == NULL )
+ if ( ((d = dom0) == NULL) || ((v = d->vcpu[0]) == NULL) )
return;
set_bit(reason_idx, &d->shared_info->arch.nmi_reason);
- if ( test_and_set_bit(_VCPUF_nmi_pending, &d->vcpu[0]->vcpu_flags) )
+ if ( test_and_set_bit(_VCPUF_nmi_pending, &v->vcpu_flags) )
raise_softirq(NMI_SOFTIRQ); /* not safe to wake up a vcpu here */
}
memcpy(info->handle, d->handle, sizeof(xen_domain_handle_t));
}
+static unsigned int default_vcpu0_location(void)
+{
+ struct domain *d;
+ struct vcpu *v;
+ unsigned int i, cpu, cnt[NR_CPUS] = { 0 };
+ cpumask_t cpu_exclude_map;
+
+ /* Do an initial CPU placement. Pick the least-populated CPU. */
+ read_lock(&domlist_lock);
+ for_each_domain ( d )
+ for_each_vcpu ( d, v )
+ if ( !test_bit(_VCPUF_down, &v->vcpu_flags) )
+ cnt[v->processor]++;
+ read_unlock(&domlist_lock);
+
+ /*
+ * If we're on a HT system, we only auto-allocate to a non-primary HT. We
+ * favour high numbered CPUs in the event of a tie.
+ */
+ cpu = first_cpu(cpu_sibling_map[0]);
+ if ( cpus_weight(cpu_sibling_map[0]) > 1 )
+ cpu = next_cpu(cpu, cpu_sibling_map[0]);
+ cpu_exclude_map = cpu_sibling_map[0];
+ for_each_online_cpu ( i )
+ {
+ if ( cpu_isset(i, cpu_exclude_map) )
+ continue;
+ if ( (i == first_cpu(cpu_sibling_map[i])) &&
+ (cpus_weight(cpu_sibling_map[i]) > 1) )
+ continue;
+ cpus_or(cpu_exclude_map, cpu_exclude_map, cpu_sibling_map[i]);
+ if ( cnt[i] <= cnt[cpu] )
+ cpu = i;
+ }
+
+ return cpu;
+}
+
long do_dom0_op(XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
{
long ret = 0;
if ( d != NULL )
{
ret = -EINVAL;
- if ( (d != current->domain) &&
+ if ( (d != current->domain) && (d->vcpu[0] != NULL) &&
test_bit(_VCPUF_initialised, &d->vcpu[0]->vcpu_flags) )
{
domain_unpause_by_systemcontroller(d);
case DOM0_CREATEDOMAIN:
{
struct domain *d;
- unsigned int pro;
domid_t dom;
- struct vcpu *v;
- unsigned int i, cnt[NR_CPUS] = { 0 };
- cpumask_t cpu_exclude_map;
static domid_t rover = 0;
/*
rover = dom;
}
- /* Do an initial CPU placement. Pick the least-populated CPU. */
- read_lock(&domlist_lock);
- for_each_domain ( d )
- for_each_vcpu ( d, v )
- if ( !test_bit(_VCPUF_down, &v->vcpu_flags) )
- cnt[v->processor]++;
- read_unlock(&domlist_lock);
-
- /*
- * If we're on a HT system, we only auto-allocate to a non-primary HT.
- * We favour high numbered CPUs in the event of a tie.
- */
- pro = first_cpu(cpu_sibling_map[0]);
- if ( cpus_weight(cpu_sibling_map[0]) > 1 )
- pro = next_cpu(pro, cpu_sibling_map[0]);
- cpu_exclude_map = cpu_sibling_map[0];
- for_each_online_cpu ( i )
- {
- if ( cpu_isset(i, cpu_exclude_map) )
- continue;
- if ( (i == first_cpu(cpu_sibling_map[i])) &&
- (cpus_weight(cpu_sibling_map[i]) > 1) )
- continue;
- cpus_or(cpu_exclude_map, cpu_exclude_map, cpu_sibling_map[i]);
- if ( cnt[i] <= cnt[pro] )
- pro = i;
- }
-
ret = -ENOMEM;
- if ( (d = domain_create(dom, pro)) == NULL )
+ if ( (d = domain_create(dom)) == NULL )
break;
memcpy(d->handle, op->u.createdomain.handle,
if ( (d = find_domain_by_id(op->u.max_vcpus.domain)) == NULL )
break;
- /*
- * Can only create new VCPUs while the domain is not fully constructed
- * (and hence not runnable). Xen needs auditing for races before
- * removing this check.
- */
- ret = -EINVAL;
- if ( test_bit(_VCPUF_initialised, &d->vcpu[0]->vcpu_flags) )
- goto maxvcpu_out;
+ /* Needed, for example, to ensure writable p.t. state is synced. */
+ domain_pause(d);
/* We cannot reduce maximum VCPUs. */
ret = -EINVAL;
ret = -ENOMEM;
for ( i = 0; i < max; i++ )
{
- if ( d->vcpu[i] == NULL )
- {
- cpu = (d->vcpu[i-1]->processor + 1) % num_online_cpus();
- if ( alloc_vcpu(d, i, cpu) == NULL )
- goto maxvcpu_out;
- }
+ if ( d->vcpu[i] != NULL )
+ continue;
+
+ cpu = (i == 0) ?
+ default_vcpu0_location() :
+ (d->vcpu[i-1]->processor + 1) % num_online_cpus();
+
+ if ( alloc_vcpu(d, i, cpu) == NULL )
+ goto maxvcpu_out;
}
ret = 0;
maxvcpu_out:
+ domain_unpause(d);
put_domain(d);
}
break;
atomic_set(&d->refcnt, 1);
spin_lock_init(&d->big_lock);
spin_lock_init(&d->page_alloc_lock);
+ spin_lock_init(&d->pause_lock);
INIT_LIST_HEAD(&d->page_list);
INIT_LIST_HEAD(&d->xenpage_list);
v->domain = d;
v->vcpu_id = vcpu_id;
v->processor = cpu_id;
- atomic_set(&v->pausecnt, 0);
v->vcpu_info = &d->shared_info->vcpu_info[vcpu_id];
+ spin_lock_init(&v->pause_lock);
v->cpu_affinity = is_idle_domain(d) ?
cpumask_of_cpu(cpu_id) : CPU_MASK_ALL;
{
struct domain *d;
struct vcpu *v;
- unsigned int vcpu_id;
+ unsigned int vcpu_id = cpu_id % MAX_VIRT_CPUS;
- if ((vcpu_id = cpu_id % MAX_VIRT_CPUS) == 0)
- {
- d = domain_create(IDLE_DOMAIN_ID, cpu_id);
- BUG_ON(d == NULL);
- v = d->vcpu[0];
- }
- else
- {
- d = idle_vcpu[cpu_id - vcpu_id]->domain;
- BUG_ON(d == NULL);
- v = alloc_vcpu(d, vcpu_id, cpu_id);
- }
+ d = (vcpu_id == 0) ?
+ domain_create(IDLE_DOMAIN_ID) :
+ idle_vcpu[cpu_id - vcpu_id]->domain;
+ BUG_ON(d == NULL);
+ v = alloc_vcpu(d, vcpu_id, cpu_id);
idle_vcpu[cpu_id] = v;
return v;
}
-struct domain *domain_create(domid_t domid, unsigned int cpu)
+struct domain *domain_create(domid_t domid)
{
struct domain *d, **pd;
- struct vcpu *v;
if ( (d = alloc_domain(domid)) == NULL )
return NULL;
if ( arch_domain_create(d) != 0 )
goto fail3;
- if ( (v = alloc_vcpu(d, 0, cpu)) == NULL )
- goto fail4;
-
d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
d->irq_caps = rangeset_new(d, "Interrupts", 0);
if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
- goto fail4; /* NB. alloc_vcpu() is undone in free_domain() */
+ goto fail4;
if ( !is_idle_domain(d) )
{
d->shutdown_code = reason;
/* Put every vcpu to sleep, but don't wait (avoids inter-vcpu deadlock). */
+ spin_lock(&d->pause_lock);
+ d->pause_count++;
+ set_bit(_DOMF_paused, &d->domain_flags);
+ spin_unlock(&d->pause_lock);
for_each_vcpu ( d, v )
- {
- atomic_inc(&v->pausecnt);
vcpu_sleep_nosync(v);
- }
get_knownalive_domain(d);
domain_shuttingdown[smp_processor_id()] = d;
void vcpu_pause(struct vcpu *v)
{
- BUG_ON(v == current);
- atomic_inc(&v->pausecnt);
+ ASSERT(v != current);
+
+ spin_lock(&v->pause_lock);
+ if ( v->pause_count++ == 0 )
+ set_bit(_VCPUF_paused, &v->vcpu_flags);
+ spin_unlock(&v->pause_lock);
+
vcpu_sleep_sync(v);
}
+void vcpu_unpause(struct vcpu *v)
+{
+ int wake;
+
+ ASSERT(v != current);
+
+ spin_lock(&v->pause_lock);
+ wake = (--v->pause_count == 0);
+ if ( wake )
+ clear_bit(_VCPUF_paused, &v->vcpu_flags);
+ spin_unlock(&v->pause_lock);
+
+ if ( wake )
+ vcpu_wake(v);
+}
+
void domain_pause(struct domain *d)
{
struct vcpu *v;
+ ASSERT(d != current->domain);
+
+ spin_lock(&d->pause_lock);
+ if ( d->pause_count++ == 0 )
+ set_bit(_DOMF_paused, &d->domain_flags);
+ spin_unlock(&d->pause_lock);
+
for_each_vcpu( d, v )
- vcpu_pause(v);
+ vcpu_sleep_sync(v);
sync_pagetable_state(d);
}
-void vcpu_unpause(struct vcpu *v)
-{
- BUG_ON(v == current);
- if ( atomic_dec_and_test(&v->pausecnt) )
- vcpu_wake(v);
-}
-
void domain_unpause(struct domain *d)
{
struct vcpu *v;
+ int wake;
- for_each_vcpu( d, v )
- vcpu_unpause(v);
+ ASSERT(d != current->domain);
+
+ spin_lock(&d->pause_lock);
+ wake = (--d->pause_count == 0);
+ if ( wake )
+ clear_bit(_DOMF_paused, &d->domain_flags);
+ spin_unlock(&d->pause_lock);
+
+ if ( wake )
+ for_each_vcpu( d, v )
+ vcpu_wake(v);
}
void domain_pause_by_systemcontroller(struct domain *d)
void send_guest_global_virq(struct domain *d, int virq)
{
int port;
+ struct vcpu *v;
struct evtchn *chn;
ASSERT(virq_is_global(virq));
- port = d->vcpu[0]->virq_to_evtchn[virq];
+ v = d->vcpu[0];
+ if ( unlikely(v == NULL) )
+ return;
+
+ port = v->virq_to_evtchn[virq];
if ( unlikely(port == 0) )
return;
}
else if ( cmd->direction == SCHED_INFO_GET )
{
+ if ( p->vcpu[0] == NULL )
+ return -EINVAL;
cmd->u.sedf.period = EDOM_INFO(p->vcpu[0])->period;
cmd->u.sedf.slice = EDOM_INFO(p->vcpu[0])->slice;
cmd->u.sedf.extratime = EDOM_INFO(p->vcpu[0])->status & EXTRA_AWARE;
{
static char *input_str[2] = { "DOM0", "Xen" };
xen_rx = !xen_rx;
- if ( SWITCH_CODE != 0 )
+ if ( (SWITCH_CODE != 0) && (dom0 != NULL) )
{
printk("*** Serial input -> %s "
"(type 'CTRL-%c' three times to switch input to %s).\n",
unsigned long vcpu_flags;
- u16 virq_to_evtchn[NR_VIRQS];
+ spinlock_t pause_lock;
+ unsigned int pause_count;
- atomic_t pausecnt;
+ u16 virq_to_evtchn[NR_VIRQS];
/* Bitmask of CPUs on which this VCPU may run. */
cpumask_t cpu_affinity;
struct rangeset *irq_caps;
unsigned long domain_flags;
+
+ spinlock_t pause_lock;
+ unsigned int pause_count;
+
unsigned long vm_assist;
atomic_t refcnt;
ASSERT(!(atomic_read(&d->refcnt) & DOMAIN_DESTROYED));
}
-extern struct domain *domain_create(
- domid_t domid, unsigned int cpu);
+extern struct domain *domain_create(domid_t domid);
extern int construct_dom0(
struct domain *d,
unsigned long image_start, unsigned long image_len,
/* VCPU is polling a set of event channels (SCHEDOP_poll). */
#define _VCPUF_polling 10
#define VCPUF_polling (1UL<<_VCPUF_polling)
+ /* VCPU is paused by the hypervisor? */
+#define _VCPUF_paused 11
+#define VCPUF_paused (1UL<<_VCPUF_paused)
/*
* Per-domain flags (domain_flags).
/* Are any VCPUs polling event channels (SCHEDOP_poll)? */
#define _DOMF_polling 5
#define DOMF_polling (1UL<<_DOMF_polling)
+ /* Domain is paused by the hypervisor? */
+#define _DOMF_paused 6
+#define DOMF_paused (1UL<<_DOMF_paused)
static inline int vcpu_runnable(struct vcpu *v)
{
- return ( (atomic_read(&v->pausecnt) == 0) &&
- !(v->vcpu_flags & (VCPUF_blocked|VCPUF_down)) &&
- !(v->domain->domain_flags & (DOMF_shutdown|DOMF_ctrl_pause)) );
+ return ( !(v->vcpu_flags &
+ (VCPUF_blocked|VCPUF_down|VCPUF_paused)) &&
+ !(v->domain->domain_flags &
+ (DOMF_shutdown|DOMF_ctrl_pause|DOMF_paused)) );
}
void vcpu_pause(struct vcpu *v);